import 'index.dart';

/// ZVT协议命令
class ZVTCommand {
  // === 命令类型 ===
  static const int CMD_TRANSACTION = 0x06; // 交易命令
  static const int CMD_AUTHORIZATION = 0x50; // 授权命令
  static const int CMD_REFUND = 0x51; // 退款命令
  static const int CMD_END_OF_DAY = 0x70; // 日终命令
  static const List<int> CMD_ABORT = [0x06, 0xB0, 0x00]; //终止
  static const int CMD_REVERSAL = 0x40; // 冲正命令
  static const int CMD_REPEAT_RECEIPT = 0x64; // 重复打印收据命令

  // === 子命令 ===
  static const int SUB_CMD_AUTH_REQUEST = 0x01; // 授权请求（销售）
  static const int SUB_CMD_REFUND_REQUEST = 0x01; // 退款请求
  static const int SUB_CMD_END_OF_DAY = 0x01; // 日终请求
  static const int SUB_CMD_REVERSAL = 0x30; // 冲正/取消交易

  // === 字段标识符 ===
  static const int FIELD_AMOUNT = 0x4F; // 金额字段
  static const int FIELD_CURRENCY = 0x49; // 货币代码字段
  static const int FIELD_PAYMENT_TYPE = 0x9C; // 支付类型字段
  static const int FIELD_TIMEOUT = 0x01; // 超时时间字段
  static const int FIELD_MAX_STATUS = 0x02; // 最大状态信息字段
  static const int FIELD_RECEIPT_NO = 0x87; // 收据号字段
  static const int FIELD_TRANSACTION_ID = 0x88; // 交易ID字段
  static const int FIELD_RESULT_CODE = 0x98; // 结果代码字段
  static const int FIELD_TLV_CONTAINER = 0x06; // TLV容器字段
  static const int FIELD_CONFIG = 0x04; // 配置字段

  // === 响应类型 ===
  static const int RESP_ACK = 0x80; // 确认响应
  static const int RESP_STATUS = 0x04; // 状态信息响应
  static const int RESP_PRINT = 0xD3; // 打印数据响应
  static const int RESP_SUCCESS = 0x0F; // 成功响应
  static const int RESP_ERROR = 0x1E; // 错误响应
  static const int RESP_FINAL_ACK = 0x0F; // 最终确认响应

  // === 命令起始标识符 ===
  static const int CMD_START = 0x02; // 命令起始标识符

  // === 状态码 ===
  static const int STATUS_TRANSACTION = 0x0F; // 交易状态
  static const int STATUS_PRINT_START = 0xD3; // 打印开始

  // === 确认码 ===
  static const int ACK_OK = 0x00; // 确认OK
  static const int ACK_ERROR = 0x01; // 确认错误

  // === 配置参数 ===
  static const int CONFIG_PARAM_1 = 0x00; // 配置参数1
  static const int CONFIG_PARAM_2 = 0x00; // 配置参数2
  static const int CONFIG_PARAM_3 = 0x00; // 配置参数3
  static const int CONFIG_PARAM_4 = 0x00; // 配置参数4

  // === 支付类型代码 ===
  static const int PAYMENT_TYPE_PTS_EXCLUDING_GELDKARTE = 0x00;
  static const int PAYMENT_TYPE_PTS_INCLUDING_GELDKARTE = 0x01;
  static const int PAYMENT_TYPE_ELV = 0x02;
  static const int PAYMENT_TYPE_GELDKARTE = 0x03;

  /// 退款子命令（定长格式，非TLV）
  static const int SUB_CMD_REFUND = 0x31; // 退款子命令
  /// 退款命令字段长度（定长格式，单位字节）
  static const int REFUND_FIELD_LENGTH = 0x0A; // 10字节
  /// 退款命令配置字段（定长格式，4字节）
  static const List<int> REFUND_CONFIG = [0x00, 0x00, 0x00, 0x04];

  /// 退款命令保留/扩展字段（定长格式，4字节）
  static const List<int> REFUND_RESERVED = [0x00, 0x00, 0x00, 0x00];

  /// 判断状态码是否为错误状态码
  static bool isErrorStatusCode(int code) {
    // 只认定官方文档中明确为错误的状态码为错误
    const errorCodes = [
      ZVTStatusCode.INVALID_CARD,
      ZVTStatusCode.SYSTEM_FAULT,
      ZVTStatusCode.PAYMENT_IMPOSSIBLE,
      ZVTStatusCode.INSUFFICIENT_BALANCE,
      ZVTStatusCode.PIN_ERROR,
      ZVTStatusCode.INSUFFICIENT_LIMIT,
      ZVTStatusCode.PIN_ATTEMPTS_EXCEEDED,
      ZVTStatusCode.CARD_DATA_ERROR,
      ZVTStatusCode.REJECTED,
      ZVTStatusCode.NOT_ACCEPTED_REMOVE_CARD,
      ZVTStatusCode.CARD_NOT_ALLOWED,
      ZVTStatusCode.CARD_UNKNOWN,
      ZVTStatusCode.CARD_EXPIRED,
      ZVTStatusCode.CARD_UNREADABLE,
      ZVTStatusCode.PROCESSING_ERROR,
      ZVTStatusCode.INVALID_CARD_REMOVE,
      ZVTStatusCode.SYSTEM_FAULT_REMOVE,
      ZVTStatusCode.PAYMENT_IMPOSSIBLE_REMOVE,
      ZVTStatusCode.INSUFFICIENT_BALANCE_REMOVE,
      ZVTStatusCode.PIN_ERROR_REMOVE,
      ZVTStatusCode.INSUFFICIENT_LIMIT_REMOVE,
      ZVTStatusCode.PIN_ATTEMPTS_EXCEEDED_REMOVE,
      ZVTStatusCode.CARD_DATA_ERROR_REMOVE,
      ZVTStatusCode.REJECTED_REMOVE,
      ZVTStatusCode.MERCHANT_LOG_FULL,
      ZVTStatusCode.DEBIT_NOTIFICATION_IMPOSSIBLE,
      ZVTStatusCode.USER_CANCELLED,
    ];
    return errorCodes.any((e) => e.code == code);
  }

  /// 获取状态码描述
  static String getStatusCodeDescription(int code) {
    return ZVTStatusCode.fromCode(code)?.statusDescription ??
        "未知状态码: 0x${code.toRadixString(16).toUpperCase()}";
  }

  // === 命令构建方法 ===

  /// 标准命令构建方法
  static List<int> buildStandardCommand(
      int commandType, Map<int, List<int>> fields) {
    List<int> cmd = [CMD_START, commandType]; // 起始标识符和命令类型

    // 构建字段数据
    List<int> fieldData = [];
    fields.forEach((fieldId, fieldValue) {
      fieldData.add(fieldId); // 字段标识符
      fieldData.add(fieldValue.length); // 字段长度
      fieldData.addAll(fieldValue); // 字段值
    });

    // 计算总长度并插入
    int totalLength = fieldData.length;
    cmd.add(totalLength);
    cmd.addAll(fieldData);

    return cmd;
  }

  /// 日结（结算）命令（06-50-03-00-00-00）
  /// 06: STX，50: 日结命令，03: 长度，00-00-00: 保留/填充
  static const List<int> SETTLEMENT_COMMAND = [
    0x06,
    0x50,
    0x03,
    0x00,
    0x00,
    0x00
  ];

  /// 构建日结（结算）命令，严格按ZVT协议定长格式
  static List<int> buildEndOfDayCommand() {
    return SETTLEMENT_COMMAND;
  }

  /// 构建中止命令
  static List<int> buildAbortCommand() {
    return CMD_ABORT;
  }

  /// 构建定长格式冲正（取消）命令，按批次号/收据号（可读性优化）
  static List<int> buildReversalCommand(String batchNumber) {
    // 验证batchNumber是否为4位十六进制数字
    if (batchNumber.length != 4 ||
        !RegExp(r'^[0-9A-Fa-f]{4}$').hasMatch(batchNumber)) {
      throw ArgumentError('batchNumber必须是4位十六进制数字，例如: 0001');
    }

    final List<int> config = [0x00, 0x00, 0x00];
    final int receiptNoHigh = int.parse(batchNumber.substring(0, 2), radix: 16);
    final int receiptNoLow = int.parse(batchNumber.substring(2, 4), radix: 16);

    return [
      CMD_TRANSACTION,
      SUB_CMD_REVERSAL,
      CMD_TRANSACTION,
      ...config,
      FIELD_RECEIPT_NO,
      receiptNoHigh, // 批次号高字节
      receiptNoLow, // 批次号低字节
    ];
  }

  // === 交易命令构建 ===
  static List<int> buildTransactionCommand(
    double amount, {
    int? currencyIsoCode,
  }) {
    List<int> amountBytes = _encodeAmount(amount); // 6字节BCD金额
    List<int> command = [
      CMD_TRANSACTION, // 06: 交易命令
      SUB_CMD_AUTH_REQUEST, // 01: 授权请求
      0x07, // 07: 字段长度
      FIELD_CONFIG, // 04: 配置字段
      amountBytes[0], // 金额高位1
      amountBytes[1], // 金额高位2
      amountBytes[2], // 金额高位3
      amountBytes[3], // 金额高位4
      amountBytes[4],
      amountBytes[5],
    ];
    if (currencyIsoCode != null) {
      List<int> currencyBytes = isoToBcd(currencyIsoCode); // 2字节BCD货币代码
      command.add(FIELD_CURRENCY); // 货币代码字段标签
      command.addAll(currencyBytes); // 货币代码数据
    }
    return command;
  }

  /// 构建退款命令（Refund 06 31）
  /// 根据ZVT协议文档第2.15节 "Refund (06 31)"
  ///
  /// [amount] 退款金额
  ///
  /// 命令格式: 06 31 07 04 [6字节BCD金额]
  /// 格式与授权交易类似，但子命令为 0x31 (退款)
  static List<int> buildRefundCommand(
    double amount, {
    int? currencyIsoCode,
  }) {
    List<int> amountBytes = _encodeAmount(amount); // 6字节BCD金额
    List<int> command = [
      CMD_TRANSACTION, // 06: 交易命令
      SUB_CMD_REFUND, // 31: 退款子命令
      0x0A, //  字段长度10字节
      ...REFUND_CONFIG, // 配置字段
      amountBytes[0], // 金额高位1
      amountBytes[1], // 金额高位2
      amountBytes[2], // 金额高位3
      amountBytes[3], // 金额高位4
      amountBytes[4],
      amountBytes[5],
    ];
    if (currencyIsoCode != null) {
      List<int> currencyBytes = isoToBcd(currencyIsoCode); // 2字节BCD货币代码
      command.add(FIELD_CURRENCY); // 货币代码字段标签
      command.addAll(currencyBytes); // 货币代码数据
    }
    return command;
  }

  // === 注册配置命令构建 ===
  /// [printPaymentReceipt] 通过支付终端进行支付功能的收据打印
  /// [printManagerReceipt] 通过支付终端进行管理功能的收据打印
  /// [sendStatusInfomation] 发送中间状态信息
  /// [allowStartPaymenttTerminal] 允许通过支付终端开始付款
  /// [allowAdminPaymentTerminal] 允许通过支付终端进行管理
  static List<int> buildRegistrationCommand({
    bool printPaymentReceipt = false,
    bool printManagerReceipt = false,
    bool sendStatusInfomation = true,
    bool allowStartPaymenttTerminal = false,
    bool allowAdminPaymentTerminal = false,
    int currencyIsoCode = 978,
  }) {
    // 计算8位configByte
    int configByte = 0xB6;
    // Bit 1: 支付收据由ECR打印
    if (printPaymentReceipt) configByte ^= 0x02;
    // Bit 2: 管理收据由ECR打印
    if (printManagerReceipt) configByte ^= 0x04;
    // Bit 3: 需要中间状态信息
    if (sendStatusInfomation) configByte ^= 0x08;
    // Bit 4: 禁止PT输入金额
    if (allowStartPaymenttTerminal) configByte ^= 0x10;
    // Bit 5: 禁止PT管理功能
    if (allowAdminPaymentTerminal) configByte ^= 0x20;
    // if (activateTLVSupport) configByte ^= 0x80; // Bit 7

    final currencyCode = isoToBcd(currencyIsoCode);
    List<int> data = [
      0x00, 0x00, 0x00, // 保留
      configByte, // 配置字节
      ...currencyCode,
    ];
    int dataLength = data.length;

    List<int> command = [CMD_TRANSACTION, 0x00, dataLength, ...data];

    return command;
  }

  /// 构建注销命令
  static List<int> buildLogOff() {
    return [CMD_TRANSACTION, 0x02, 0x00];
  }

  ///构建重新打印票据
  static List<int> buildRepeatReceipt() {
    return [CMD_TRANSACTION, 0x20, 0x03, 0x00, 0x00, 0x00];
  }

  // === 金额编码 ===
  static List<int> encodeAmount(double amount) {
    return _encodeAmount(amount);
  }

  static List<int> _encodeAmount(double amount) {
    // 将金额转换为分（整数）
    int amountInCents = (amount * 100).round();
    // 转换为12位字符串，右对齐，左补0
    String amountStr = amountInCents.toString().padLeft(12, '0');
    return _bcdEncode(amountStr);
  }

  // === BCD编码 ===
  static List<int> _bcdEncode(String number) {
    List<int> result = [];
    for (int i = 0; i < number.length; i += 2) {
      int high = int.parse(number[i]);
      int low = i + 1 < number.length ? int.parse(number[i + 1]) : 0;
      result.add((high << 4) | low);
    }
    return result;
  }

  // === 字节数组转十六进制字符串 ===
  static String bytesToHex(List<int> bytes) {
    return bytes
        .map((byte) => byte.toRadixString(16).padLeft(2, '0'))
        .join(' ')
        .toUpperCase();
  }

  // === 最终确认消息 ===
  static const int FINAL_ACK_CMD = 0x06; // 最终确认命令
  static const int FINAL_ACK_SUB = 0x0F; // 最终确认子命令
  static const int FINAL_ACK_DATA = 0x00; // 最终确认数据
  static const List<int> FINAL_ACK_MESSAGE = [
    FINAL_ACK_CMD,
    FINAL_ACK_SUB,
    FINAL_ACK_DATA
  ]; // 06-0F-00
  static const List<int> FINAL_ACK_RESPONSE = [
    RESP_ACK,
    ACK_OK,
    ACK_OK
  ]; // 80-00-00

  static List<int> isoToBcd(int isoCode) {
    String s = isoCode.toString().padLeft(4, '0'); // 保证4位
    return [
      int.parse(s.substring(0, 2), radix: 16), // 前两位
      int.parse(s.substring(2, 4), radix: 16), // 后两位
    ];
  }
}
